package com.lancoo.ccas52.schedues;

import cn.hutool.core.collection.CollUtil;
import com.lancoo.ccas52.entity.*;
import com.lancoo.ccas52.pojo.dto.RedisStudentOptionalClass;
import com.lancoo.ccas52.service.*;
import com.lancoo.ccas52.service.impl.StudentServiceImpl;
import com.lancoo.ccas52.util.RedisUtil;
import lombok.extern.slf4j.Slf4j;
import org.redisson.api.RAtomicLong;
import org.redisson.api.RedissonClient;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.stream.Collectors;

/**
 * @ClassName syncSchedule
 * @Description 定时同步数据
 * @Author quin
 * @Date 2023/6/24 15:29
 */
@Component
@Slf4j
@EnableAsync(proxyTargetClass = true)
public class SyncSchedule {

    @Resource
    private StudentServiceImpl studentService;
    @Resource
    private TaskInfoService taskInfoService;
    @Resource
    private CssTaskRoundService cssTaskRoundService;
    @Resource
    private CssRangeService cssRangeService;
    @Resource
    private CssTaskInfoService cssTaskInfoService;

    @Resource
    private RedissonClient redissonClient;

    /**
     * 同步选课学生
     */
    @Scheduled(cron = "0 0 4 * * ?")
    public void sendSelectCourseEndMsg() {
        // 定义分布式锁的名称
        String lockKey = "sendSelectCourseEndMsg";

        // 获取分布式锁使用 SETNX（仅在键不存在时设置）
        RAtomicLong lock = redissonClient.getAtomicLong(lockKey);
        boolean locked = lock.compareAndSet(0, 1);

        try {
            if (locked) {
                // 获取到锁，执行任务逻辑
                List<TaskInfo> taskInfos = taskInfoService.list();
                for (TaskInfo taskInfo : taskInfos) {
                    studentService.syncTeachingClassStudent(taskInfo.getTaskId());
                }
            } else {
                // 锁已被其他实例获取
                log.info("同步选课学生任务已经在其他节点执行，本节点无需执行");
            }
        } finally {
            // 任务完成后释放锁（解锁）
            if (locked) {
                lock.compareAndSet(1, 0);
            }
        }
    }

    /**
     * 每小时执行一次
     * redis数据预热 缓存学生可选教学班以及教学班详情数据
     */
    @Scheduled(cron = "0 0 * * * ?")
    public void preheatingCourseSelection() {
        LocalDateTime now = LocalDateTime.now();
        //获取当前时间到24小时内要开始的轮次
        List<CssTaskRound> cssTaskRounds = cssTaskRoundService.lambdaQuery().ge(CssTaskRound::getBeginTime, now)
                .le(CssTaskRound::getBeginTime, now.plusHours(2)).list();
        cssTaskRounds.forEach(cssTaskRound -> {
            CssTaskInfo cssTaskInfo = cssTaskInfoService.getById(cssTaskRound.getCssTaskId());
            log.info("开始预热选课任务：{},轮次id:{}", cssTaskInfo.getCssTaskName(), cssTaskRound.getId());
            Integer taskId = cssTaskInfo.getTaskId();
            //  1在线选课; 3:预选教学班
            Integer teachingClassType = 1;
            if (cssTaskInfo.getType().equals(1)){
                teachingClassType = 3;
            }
            //获取选课范围 一对多范围设置
            List<CssRange> cssRangeList = cssRangeService.lambdaQuery().eq(CssRange::getRoundId, cssTaskRound.getId()).list();
            List<String> collegeIds = cssRangeList.stream().filter(cssRange -> cssRange.getOptionIdentify().equals(1)).map(CssRange::getOptionId).collect(Collectors.toList());
            List<String> gradeIds = cssRangeList.stream().filter(cssRange -> cssRange.getOptionIdentify().equals(2)).map(CssRange::getOptionId).collect(Collectors.toList());
            //获取该轮次全部学生
            List<Long> studentIds = studentService.lambdaQuery().in(CollUtil.isNotEmpty(collegeIds), Student::getCollegeId, collegeIds)
                    .in(CollUtil.isNotEmpty(gradeIds), Student::getGradeId, gradeIds)
                    .eq(Student::getTaskId, cssTaskInfo.getTaskId()).list()
                    .stream().map(Student::getStudentId).collect(Collectors.toList());
            List<Long> teachingClassIds = new ArrayList<>();
            for (Long studentId : studentIds) {
                Student student = studentService.getById(studentId);
                //获取全部可选教学班
                HashMap<Long, RedisStudentOptionalClass> redisStudentOptionalClassHashMap = studentService.getAvailableTeachingClass(taskId, teachingClassType, student);
                teachingClassIds.addAll(redisStudentOptionalClassHashMap.keySet());
            }
            studentService.getTeachingClassDetail(taskId, teachingClassIds.stream().distinct().collect(Collectors.toList()));
        });

    }
}
